<?php

/**
 * 异步线程队列
 * 协程处理
 * TaskServer
 */
namespace App\Service\TaskServer;

use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\WaitGroup;
use App\Service\HttpServer\HttpCurl;
use App\Service\BaseService;
use App\Model\PssLogModel\MicroServiceLog;
use Hyperf\Task\Annotation\Task;
use App\Service\Code\Normal;
use App\Model\PssLogModel\MicroServiceQueryLog;

class TaskWorker extends BaseService
{
    /**
     * @Task
     * 进行协程并发调用http请求
     * @param array $data
     */
    public function handle( $data = [] )
    {
        $result = [];
        $count = count($data);
        $wg = new WaitGroup();
        $wg->add($count);
        foreach ($data as $key => $val ) {
            co(function () use ($wg,$key,$val,& $result) {
                $start_time = microtime(true);
                $res = HttpCurl::instance()->apiRequest($val['url'],$val['data'],$val['method'],$val['format'],$val['header']??[]);
                $used_time = bcsub(microtime(true), $start_time,3);
                $result[$key] = [
                    'request'   => $val,
                    'response'  => $res,
                    'used_time' => $used_time,
                ];
                
                $response_data = json_decode($res['result'],true);
                $response_data = !empty($response_data) ? json_encode($response_data,JSON_UNESCAPED_UNICODE) : $res['result'];
                //写入日志
                MicroServiceLog::instance()->addLog([
                    'interface_code'    => $val['tag'],
                    'request_url'       => $val['url'],
                    'request_param'     => json_encode($val['data'],JSON_UNESCAPED_UNICODE),
                    'response_code'     => $res['httpCode'],
                    'response_data'     => $response_data,
                    'req_used_time'     => $used_time,
                ]);                
                $wg->done();
            });
        }
        
        $wg->wait();
        return $result;
    }
    
    /**
     * 进行协程并发调用http请求
     * @param array $data
     */
    public function handleDiableTask( $data = [] )
    {
        $result = [];
        $count = count($data);
        $wg = new WaitGroup();
        $wg->add($count);
        foreach ($data as $key => $val ) {
            co(function () use ($wg,$key,$val,& $result) {
                $start_time = microtime(true);
                $res = HttpCurl::instance()->apiRequest($val['url'],$val['data'],$val['method'],$val['format'],$val['header']??[]);
                $used_time = bcsub(microtime(true), $start_time,3);
                $result[$key] = [
                    'request'   => $val,
                    'response'  => $res,
                    'used_time' => $used_time,
                ];
        
                $response_data = json_decode($res['result'],true);
                $response_data = !empty($response_data) ? json_encode($response_data,JSON_UNESCAPED_UNICODE) : $res['result'];
                //写入日志
                if (!isset($val['is_not_log'])){
                    MicroServiceQueryLog::instance()->addLog([
                        'interface_code'    => $val['tag'],
                        'request_url'       => $val['url'],
                        'request_param'     => json_encode($val['data'],JSON_UNESCAPED_UNICODE),
                        'response_code'     => $res['httpCode'],
                        'response_data'     => $response_data,
                        'req_used_time'     => $used_time,
                    ]);
                }
                $wg->done();
            });
        }
        
        $wg->wait();
        return $result;
    }
    
    /**
     * 订单支付异步队列池
     * 开始进行订单分组推送支付订单
     * 1、去刷单（支付单申报和订单支付申报）
     * 2、去扣除预付款，不用申报
     * 3、自建仓库不需要推送订单
     *      
     * 订单取消异步队列池
     * 开始进行订单分组推送支付订单
     * 1、取消订单结果推送上游
     * 2、恢复仓库库存
     * 
     * 订单售后异步队列池
     * 开始进行订单分组推送支付订单
     * 1、取消订单结果推送上游
     * 2、恢复仓库库存
     */
    public function singleOrder( $param = [] )
    {
        if( empty($param['suppplierList']) || 
            empty($param['newOrderGoods']) || 
            empty($param['supplierOrderList']) || 
            empty($param['order']) || 
            empty($param['binfo']) || 
            empty($param['serviceClass']) ||
            empty($param['serviceMethod'])
        ) {
            return [Normal::returnCode(Normal::FAIL,"except param suppplierList or newOrderGoods or supplierOrderList or order or binfo or serviceMethod or serviceClass")];
        }
        
        //按照订单个数开启协程
        $orderList = $param['supplierOrderList'];
        $result = [];
        $count = count($orderList);
        $wg = new WaitGroup();
        $wg->add($count);
        foreach ($orderList as $key => $orderInfo ) 
        {
            co(function () use ($wg,$key,$orderInfo,$param,& $result) 
            {
                $suppplierList  = $param['suppplierList'];
                $orderGoodsList = $param['newOrderGoods'];
                $order          = $param['order'];
                $binfo          = $param['binfo'];
                $serviceClass   = $param['serviceClass'];
                $orderRefund    = $param['orderRefund'] ?? [];
                if( isset($suppplierList[$orderInfo['company_id']]) ) 
                {
                    $result[] = $serviceClass::instance()->{$param['serviceMethod']}(
                    [
                        'companyInfo'   => $suppplierList[$orderInfo['company_id']],
                        'supplierOrder' => $orderInfo,
                        'orderGoods'    => $orderGoodsList[$orderInfo['id']],
                        'order'         => $order,
                        'binfo'         => $binfo,
                        'orderRefund'   => $orderRefund
                    ]);
                } 
                else 
                {
                    $result[] = Normal::returnCode(Normal::FAIL,"供应商账号ID:{$orderInfo['company_id']}不存在，请核对！");
                }
                $wg->done();
            });
        }
        
        $wg->wait();
        return $result;
    }
    
    /**
     * 异步通知回调结果
     * @param object $class
     * @param string $method
     * @param array $data
     * @return mixed
     */
    public function addWebNotifyTask( $class,$method = 'handle',$data = [] )
    {
        $container  = ApplicationContext::getContainer();
        $task       = $container->get($class);
        return $task->{$method}($data);
    }
    
    /**
     * 加入异步队列池
     * @param array $param
     * @return mixed
     */
    public function addTask($data= [],$taskMethod = 'handle' )
    {
        $container  = ApplicationContext::getContainer();
        $task       = $container->get(TaskWorker::class);
        return $task->{$taskMethod}($data);
    }
}